/*
 * Copyright (C) 2018 The Asiainfo-Ability Authors
 *
 *      Licensed under the Apache License, Version 2.0 (the "License");
 *      you may not use this file except in compliance with the License.
 *      You may obtain a copy of the License at
 *
 *          http://www.apache.org/licenses/LICENSE-2.0
 *
 *      Unless required by applicable law or agreed to in writing, software
 *      distributed under the License is distributed on an "AS IS" BASIS,
 *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *      See the License for the specific language governing permissions and
 *      limitations under the License.
 */

package org.asiainfo.ability.gateway.filter;

import com.netflix.hystrix.exception.HystrixTimeoutException;
import com.netflix.zuul.context.RequestContext;


import org.asiainfo.ability.base.code.SystemCode;
import org.asiainfo.ability.base.utils.Response;
import org.asiainfo.ability.gateway.context.AbilityRequestContext;
import org.asiainfo.ability.gateway.service.AbilityGatewayFacade;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.SocketTimeoutException;
import java.nio.charset.Charset;

/**
 * @Author: visen
 * @Date: 2018/1/16
 * @Description:
 */
@Component
public class ServiceFallbackProvider implements FallbackProvider {


    @Autowired
    private AbilityGatewayFacade gatewayFacade;

    @Override
    public String getRoute() {
        return null;
    }

    @Override
    public ClientHttpResponse fallbackResponse() {
        return null;
    }

    private static final boolean isInstanceOfTimeout(Throwable t) {
        if (t instanceof HystrixTimeoutException) {
            return true;
        }
        int j = 0;
        while (t.getCause() != null && j++ < 4) {
            t = t.getCause();
            if (t instanceof SocketTimeoutException) {
                return true;
            }
        }
        return false;
    }

    public static final class ClientHttpResponseDirty implements ClientHttpResponse {

        private Throwable cause;
        private ByteArrayInputStream body;

        public ClientHttpResponseDirty(final AbilityGatewayFacade gatewayFacade, Throwable cause) {
            this.cause = cause;
            //cause.getCause()
            RequestContext ctx = RequestContext.getCurrentContext();

            AbilityRequestContext requestContext = (AbilityRequestContext) ctx.get(
                    AbilityRequestContext.CONTEXT_KEY);
            ctx.set("isSuccess", false);
            if (isInstanceOfTimeout(cause)) {
                this.body = new ByteArrayInputStream(Response.error(SystemCode.timeout).getBytes());
                gatewayFacade.setTimeout(requestContext);
                ctx.set("errorSummary", SystemCode.timeout.getName());
            } else {
                ctx.set("errorSummary", SystemCode.invalid_ability.getName());
                this.body = new ByteArrayInputStream(
                        Response.error(String.valueOf(SystemCode.invalid_ability.getValue())
                                , new StringBuilder("[能力: ")
                                        .append(requestContext.getAbility().getName())
                                        .append(", 服务: ")
                                        .append(ctx.get(FilterConstants.SERVICE_ID_KEY))
                                        .append("] 不可用, 请联系厂家解决").toString()).getBytes());
            }

        }

        @Override
        public HttpStatus getStatusCode() throws IOException {
            return HttpStatus.BAD_REQUEST;
        }

        @Override
        public int getRawStatusCode() throws IOException {
            return this.getStatusCode().value();
        }

        @Override
        public String getStatusText() throws IOException {
            return this.getStatusCode().getReasonPhrase();
        }

        @Override
        public void close() {

        }

        @Override
        public InputStream getBody() throws IOException {
            return this.body;
        }

        @Override
        public HttpHeaders getHeaders() {
            HttpHeaders headers = new HttpHeaders();
            MediaType mt = new MediaType("application", "json", Charset.forName("UTF-8"));
            headers.setContentType(mt);

            return headers;
        }
    }

    @Override
    public ClientHttpResponse fallbackResponse(final Throwable cause) {
        return new ClientHttpResponseDirty(gatewayFacade, cause);
    }
}